// SDL2_06 [OpenGL ES Triangle 3].nova // OpenGL ES triangle coloured via a buffer object from the main program. // Using namespace declarations. using library.emscripten; using library.opengl; using library.sdl2; // The application class. class SDL2_06_OpenGL_ES_Triangle_3 { // Static data members. private static SDL_Window w; private static SDL_Renderer r; private static SDL_GLContext c; // Application class's "main" function. public static void main( String[] args ) { Stream.writeLine( "SDL2_06 [OpenGL ES Triangle 3].nova" ); // Disable the emscripten full-screen controls. Emscripten.disableControls( ); // Setup SDL. SDL2.SDL_Init( SDL2.SDL_INIT_VIDEO ); SDL2.SDL_GL_SetAttribute( SDL2.SDL_GL_CONTEXT_MAJOR_VERSION, 2 ); SDL2.SDL_GL_SetAttribute( SDL2.SDL_GL_CONTEXT_MINOR_VERSION, 0 ); SDL2.SDL_GL_SetAttribute( SDL2.SDL_GL_DOUBLEBUFFER, 1 ); SDL2.SDL_GL_SetAttribute( SDL2.SDL_GL_DEPTH_SIZE, 24 ); w = SDL2.SDL_CreateWindow( "SDL2_06_OpenGL_ES_Triangle_3", SDL2.SDL_WINDOWPOS_CENTERED, SDL2.SDL_WINDOWPOS_CENTERED, 640, 480, SDL2.SDL_WINDOW_OPENGL | SDL2.SDL_WINDOW_RESIZABLE ); // Check for a null reference. if ( w == null ) { // Output an error message. Stream.writeLine( "Failed to create window: " + SDL2.SDL_GetError( ) ); // Abort the application. return; } r = SDL2.SDL_CreateRenderer( w, -1, SDL2.SDL_RENDERER_ACCELERATED | SDL2.SDL_RENDERER_PRESENTVSYNC ); c = SDL2.SDL_GL_CreateContext( w ); // Set the background colour. OpenGL.glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // Black. // Shader sources. String vertexSource = "attribute vec2 position; \n" + "attribute vec4 colour; \n" + "varying vec4 varColor; \n" + " \n" + "void main( ) \n" + "{ \n" + " gl_Position = vec4( position.xy, 1.0, 1.0 ); \n" + " varColor = colour; \n" + "} \n"; String fragmentSource = "precision mediump float; \n" + "varying vec4 varColor; \n" + " \n" + "void main( ) \n" + "{ \n" + " gl_FragColor = varColor; \n" + "} \n"; // Create and compile the vertex shader. uint vertexShader = OpenGL.glCreateShader( OpenGL.GL_VERTEX_SHADER ); OpenGL.glShaderSource( vertexShader, vertexSource ); OpenGL.glCompileShader( vertexShader ); // Create and compile the fragment shader. uint fragmentShader = OpenGL.glCreateShader( OpenGL.GL_FRAGMENT_SHADER ); OpenGL.glShaderSource( fragmentShader, fragmentSource ); OpenGL.glCompileShader( fragmentShader ); // Link the vertex and fragment shader into a shader program. uint shaderProgram = OpenGL.glCreateProgram( ); OpenGL.glAttachShader( shaderProgram, vertexShader ); OpenGL.glAttachShader( shaderProgram, fragmentShader ); OpenGL.glLinkProgram( shaderProgram ); OpenGL.glUseProgram( shaderProgram ); // The vertex and colour data for the triangle. float[] vertices = { 0.0f, 0.5f, 0.5f, -0.5f, -0.5f, -0.5f }; float[] colours = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f }; // Create two vertex buffer objects. uint[] vbos = new uint[ 2 ]; OpenGL.glGenBuffers( 2, vbos ); // Pass the vertices to the buffer object. OpenGL.glBindBuffer( OpenGL.GL_ARRAY_BUFFER, vbos[ 0 ] ); OpenGL.glBufferData( OpenGL.GL_ARRAY_BUFFER, vertices, OpenGL.GL_STATIC_DRAW ); // Specify the layout of the vertex data. int posAttrib = OpenGL.glGetAttribLocation( shaderProgram, "position" ); OpenGL.glVertexAttribPointer( (uint)posAttrib, 2, OpenGL.GL_FLOAT, false, 0, 0 ); OpenGL.glEnableVertexAttribArray( (uint)posAttrib ); // Pass the colours to the buffer object. OpenGL.glBindBuffer( OpenGL.GL_ARRAY_BUFFER, vbos[ 1 ] ); OpenGL.glBufferData( OpenGL.GL_ARRAY_BUFFER, colours, OpenGL.GL_STATIC_DRAW ); // Specify the layout of the colour data. int colAttrib = OpenGL.glGetAttribLocation( shaderProgram, "colour" ); OpenGL.glVertexAttribPointer( (uint)colAttrib, 3, OpenGL.GL_FLOAT, false, 0, 0 ); OpenGL.glEnableVertexAttribArray( (uint)colAttrib ); // Check for the emscripten environment. if ( Emscripten.isActive( ) ) { int simulate_infinite_loop = 1; // Call the function repeatedly. int fps = -1; // Call the function as fast as the browser wants to render (typically 60fps). Emscripten.setMainLoop( renderFrame, fps, simulate_infinite_loop ); } else { // Rendering and event processing loop. do { SDL_Event e = SDL2.SDL_PollEvent( ); if ( e != null ) if ( e.id == SDL2.SDL_QUIT ) break; renderFrame( ); } while( true ); } // Shutdown app. OpenGL.glDeleteBuffers( 2, vbos ); OpenGL.glDeleteProgram( shaderProgram ); OpenGL.glDeleteShader( vertexShader ); OpenGL.glDeleteShader( fragmentShader ); SDL2.SDL_GL_DeleteContext( c ); SDL2.SDL_DestroyRenderer( r ); SDL2.SDL_DestroyWindow( w ); SDL2.SDL_Quit( ); } public static void renderFrame( ) { OpenGL.glClear( OpenGL.GL_COLOR_BUFFER_BIT ); // Draw a triangle from the 3 vertices. OpenGL.glDrawArrays( OpenGL.GL_TRIANGLES, 0, 3 ); SDL2.SDL_GL_SwapWindow( w ); } }